<?php

namespace luguohuakai\wechat;

use Exception;
use luguohuakai\cache\Cache;
use luguohuakai\func\Func;

class WeChat
{
    public $app_id;
    public $app_secret;

    public $aes_key;

    public function __construct($app_id, $app_secret)
    {
        $this->app_id = $app_id;
        $this->app_secret = $app_secret;
    }

    /**
     * @param array $conf ['app_id' => 'xxx', 'app_secret' => 'xxx']
     * @return WeChat
     * @throws Exception
     */
    public static function init(array $conf): WeChat
    {
        if (empty($conf['app_id']) || empty($conf['app_secret'])) throw new Exception('app_id or app_secret must be set.');
        $instance = new self($conf['app_id'], $conf['app_secret']);
        // 可以设置其它参数
        if (isset($conf['aes_key'])) $instance->aes_key = $conf['aes_key'];
        return $instance;
    }

    /**
     * @param $data
     * @param string $level info/warn/error
     * @return void
     */
    private function logs($data, string $level = 'error')
    {
        Func::logs('wechat', $data, 'human-readable', FILE_APPEND, 'month', $level);
    }

    /**
     * 发起请求并记录日志
     * @param $url
     * @param string $method
     * @param array $data
     * @return mixed
     */
    protected function req($url, string $method = 'get', array $data = [])
    {
        $this->logs("Request:$method:$url:" . json_encode($data, JSON_UNESCAPED_UNICODE), 'info');
        if ($method === 'get') {
            $rs = Func::get($url, $data);
        } else {
            $rs = Func::post($url, $data, [], 2);
        }
        $this->logs("Response:" . print_r($rs, true), 'info');
        return $rs;
    }

    /**
     * 获取access_token
     * @return array|mixed|string|string[]
     */
    public function accessToken()
    {
        $c = new Cache;
        $access_token = $c->get('wx_access_token');
        if ($access_token) return $access_token;

        $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=$this->app_id&secret=$this->app_secret";
        $rs = $this->req($url);
        if ($rs) {
            $res = json_decode($rs);
            if ($res) {
                if (isset($res->access_token)) {
                    $c->set('wx_access_token', $res->access_token, $res->expires_in);
                    return $res->access_token;
                } else {
                    $this->logs('request error: no access_token: ' . print_r($rs, true));
                }
            } else {
                $this->logs('json_decode error: ' . print_r($rs, true));
            }
        } else {
            $this->logs('request wechat server error: ' . $url);
        }
        return '';
    }

    /**
     * 公众号:获取模板列表
     * @return mixed
     */
    public function getAllPrivateTemplate()
    {
        $url = 'https://api.weixin.qq.com/cgi-bin/template/get_all_private_template?access_token=';

        return $this->req($url . $this->accessToken());
        //{
        //	"template_list": [
        //		{
        //			"template_id": "8dF4sI_-6YCHy6upfG_X7FgkvCql8-scuqfMvAOok8w",
        //			"title": "订阅模板消息",
        //			"primary_industry": "",
        //			"deputy_industry": "",
        //			"content": "{{content.DATA}}",
        //			"example": ""
        //		},
        //		{
        //			"template_id": "qN41EA7rTEPJUBUKLeG0kcRHWP4w1Clc17MahepHeS8",
        //			"title": "设备告警通知",
        //			"content": "项目名称:{{thing95.DATA}}\n告警对象:{{thing2.DATA}}\n告警原因:{{thing70.DATA}}\n事件状态:{{phrase9.DATA}}\n告警时间:{{time3.DATA}}\n",
        //			"example": "项目名称:污水采集\n告警对象:黄礼拜-男-99岁\n告警原因:空调面板低温告警啦\n事件状态:待调度\n告警时间:2022年11月22日 22:22:22\n"
        //		}
        //	]
        //}
    }

    /**
     * 公众号:发送模板消息
     * @param $open_id
     * @param $template_id
     * @param array $data e.g.: ['thing95' => ['value' => '第一个参数'], 'thing2' => ['value' => '第二个参数']]
     * @return mixed
     */
    public function send($open_id, $template_id, array $data)
    {
        $url = 'https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=';

        $post_data = [
            'touser' => $open_id,
            'template_id' => $template_id,
            'data' => $data
        ];

        return $this->req($url . $this->accessToken(), 'post', $post_data);
    }

    /**
     * 公众号:获取用户列表
     * @return mixed
     */
    public function userGet()
    {
        $url = 'https://api.weixin.qq.com/cgi-bin/user/get?access_token=';
        return $this->req($url . $this->accessToken());
        //{
        //	"total": 890,
        //	"count": 890,
        //	"data": {
        //		"openid": [
        //			"oh53Pv-l-QyKXz5l0xdrCNxV6b5c",
        //          ...
        //			"oh53Pvy5glP5y6BkuTCsPD1uJRTI"
        //		]
        //	},
        //	"next_openid": "oh53Pvy5glP5y6BkuTCsPD1uJRTI"
        //}
    }

    /**
     * 开发者查询rid信息
     * @param $rid
     * @return mixed
     */
    public function ridGet($rid)
    {
        $url = 'https://api.weixin.qq.com/cgi-bin/openapi/rid/get?access_token=';
        return $this->req($url . $this->accessToken(), 'post', ['rid' => $rid]);
    }

    /**
     * 公众号:创建自定义菜单
     * @param array $data
     * @return mixed
     */
    public function menuCreate(array $data)
    {
        $url = 'https://api.weixin.qq.com/cgi-bin/menu/create?access_token=';

        return $this->req($url . $this->accessToken(), 'post', $data);
    }

    /**
     * 公众号:查询菜单
     * @param array $data
     * @return mixed
     */
    public function getCurrentSelfMenuInfo(array $data)
    {
        $url = 'https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info?access_token=';

        return $this->req($url . $this->accessToken());
    }

    ///////////////网页授权////////////////

    /**
     * 第一步：用户同意授权，获取code
     * @param string $redirect_uri 授权后重定向的回调链接地址， 请使用 urlEncode 对链接进行处理
     * @param string $scope 应用授权作用域，snsapi_base （不弹出授权页面，直接跳转，只能获取用户openid），snsapi_userinfo （弹出授权页面，可通过openid拿到昵称、性别、所在地。并且， 即使在未关注的情况下，只要用户授权，也能获取其信息 ）
     * @param string $state 重定向后会带上state参数，开发者可以填写a-zA-Z0-9的参数值，最多128字节
     * @return string 如果用户同意授权，页面将跳转至 redirect_uri/?code=CODE&state=STATE。
     */
    public function getCode(string $redirect_uri, string $scope = 'snsapi_userinfo', string $state = 'STATE'): string
    {
        $redirect_uri = urlencode($redirect_uri);
        return "https://open.weixin.qq.com/connect/oauth2/authorize?appid=$this->app_id&redirect_uri=$redirect_uri&response_type=code&scope=$scope&state=$state#wechat_redirect";
    }

    /**
     * 第二步：通过code换取网页授权access_token
     * @param $code
     * @return mixed
     */
    public function oauth2AccessToken($code)
    {
        $url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=$this->app_id&secret=$this->app_secret&code=$code&grant_type=authorization_code";
        return $this->req($url);
        //{
        //  "access_token":"ACCESS_TOKEN",
        //  "expires_in":7200,
        //  "refresh_token":"REFRESH_TOKEN",
        //  "openid":"OPENID",
        //  "scope":"SCOPE",
        //  "is_snapshotuser": 1,
        //  "unionid": "UNIONID"
        //}
    }

    /**
     * 第三步：刷新access_token（如果需要）
     * @param $refresh_token
     * @return mixed
     */
    public function oauth2RefreshToken($refresh_token)
    {
        $url = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=$this->app_id&grant_type=refresh_token&refresh_token=$refresh_token";
        return $this->req($url);
        //{
        //  "access_token":"ACCESS_TOKEN",
        //  "expires_in":7200,
        //  "refresh_token":"REFRESH_TOKEN",
        //  "openid":"OPENID",
        //  "scope":"SCOPE"
        //}
    }

    /**
     * 第四步：拉取用户信息(需scope为 snsapi_userinfo)
     * @param $access_token
     * @param $openid
     * @return mixed
     */
    public function userInfo($access_token, $openid)
    {
        $url = "https://api.weixin.qq.com/sns/userinfo?access_token=$access_token&openid=$openid&lang=zh_CN";
        return $this->req($url);
        //{
        //  "openid": "OPENID",
        //  "nickname": NICKNAME,
        //  "sex": 1,
        //  "province":"PROVINCE",
        //  "city":"CITY",
        //  "country":"COUNTRY",
        //  "headimgurl":"https://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
        //  "privilege":[ "PRIVILEGE1" "PRIVILEGE2"     ],
        //  "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
        //}
    }

    /**
     * 附：检验授权凭证（access_token）是否有效
     * @param $access_token
     * @param $open_id
     * @return mixed
     */
    public function snsAuth($access_token, $open_id)
    {
        $url = "https://api.weixin.qq.com/sns/auth?access_token=$access_token&openid=$open_id";
        return $this->req($url);
        // {"errcode":0,"errmsg":"ok"}
    }
}